#!/usr/bin/env python3
"""
Scaffold integration test files for a Spring AI example
Usage: python3 scripts/scaffold_integration_test.py <module-path> [--complexity simple|complex|mcp]
"""

import sys
import pathlib
import json
import argparse
import time
from typing import Dict, List

def get_module_info(module_path: str) -> Dict:
    """Extract information about the module"""
    module_dir = pathlib.Path(module_path)
    module_name = module_dir.name
    
    # Convert kebab-case to PascalCase for Java class name
    class_name = ''.join(word.capitalize() for word in module_name.replace('-', ' ').replace('_', ' ').split())
    
    # Try to determine if it's a Spring Boot app
    pom_path = module_dir / "pom.xml"
    has_spring_boot = False
    if pom_path.exists():
        pom_content = pom_path.read_text()
        has_spring_boot = "spring-boot" in pom_content.lower()
    
    return {
        'module_name': module_name,
        'class_name': class_name,
        'has_spring_boot': has_spring_boot,
        'module_dir': module_dir
    }

def get_config_template(complexity: str) -> Dict:
    """Get configuration template based on complexity"""
    templates = {
        'simple': {
            "timeoutSec": 120,
            "successRegex": ["BUILD SUCCESS", "Started.*Application"],
            "requiredEnv": ["OPENAI_API_KEY"]
        },
        'complex': {
            "timeoutSec": 300,  
            "successRegex": ["BUILD SUCCESS", "Started.*Application", "EVALUATION:\\\\s+PASS"],
            "requiredEnv": ["OPENAI_API_KEY"]
        },
        'mcp': {
            "timeoutSec": 300,
            "successRegex": ["BUILD SUCCESS", "Started.*Application", "MCP Initialized", "Connected"],
            "requiredEnv": ["OPENAI_API_KEY"],
            "setupCommands": ["./create-database.sh"]
        }
    }
    return templates.get(complexity, templates['simple'])

def generate_jbang_launcher(module_info: Dict, config: Dict) -> str:
    """Generate JBang launcher script"""
    class_name = module_info['class_name']
    module_name = module_info['module_name']
    
    # Handle optional fields
    setup_commands = config.get('setupCommands', [])
    cleanup_commands = config.get('cleanupCommands', [])
    
    setup_code = ""
    if setup_commands:
        setup_code = f"""
        // Run setup commands if specified
        if (cfg.setupCommands() != null) {{
            for (String setupCmd : cfg.setupCommands()) {{
                out.println("🔧 Running setup: " + setupCmd);
                runCommand(setupCmd.split("\\\\s+"), 60); // 1 minute timeout for setup
            }}
        }}
        """
    
    cleanup_code = ""
    if cleanup_commands:
        cleanup_code = f"""
        // Run cleanup commands if specified
        if (cfg.cleanupCommands() != null) {{
            for (String cleanupCmd : cfg.cleanupCommands()) {{
                out.println("🧹 Running cleanup: " + cleanupCmd);
                try {{
                    runCommand(cleanupCmd.split("\\\\s+"), 30);
                }} catch (Exception e) {{
                    err.println("⚠️  Cleanup failed: " + e.getMessage());
                }}
            }}
        }}
        """
    
    return f'''///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.zeroturnaround:zt-exec:1.12
//DEPS com.fasterxml.jackson.core:jackson-databind:2.17.1
//JAVA 17
//FILES ExampleInfo.json

/*
 * Integration test launcher for {module_name}
 * Generated by scaffold_integration_test.py on {time.strftime('%Y-%m-%d %H:%M:%S')}
 */

import com.fasterxml.jackson.databind.*;
import org.zeroturnaround.exec.*;
import java.nio.file.*;
import java.util.concurrent.TimeUnit;
import static java.lang.System.*;

record ExampleInfo(
    int timeoutSec, 
    String[] successRegex, 
    String[] requiredEnv,
    String[] setupCommands,
    String[] cleanupCommands
) {{}}

public class Run{class_name} {{
    
    public static void main(String... args) throws Exception {{
        Path configPath = Path.of("integration-tests/ExampleInfo.json");
        ExampleInfo cfg = new ObjectMapper().readValue(configPath.toFile(), ExampleInfo.class);

        // Verify required environment variables
        for (String envVar : cfg.requiredEnv()) {{
            if (getenv(envVar) == null) {{
                err.println("❌ Missing required environment variable: " + envVar);
                exit(1);
            }}
        }}

        try {{{setup_code}
            
            // Build and run the main application
            out.println("🏗️  Building {module_name}...");
            runCommand(new String[]{{"./mvnw", "clean", "package", "-q", "-DskipTests"}}, 300);

            out.println("🚀 Running {module_name}...");
            Path logFile = Files.createTempFile("integration-test", ".log");
            
            ProcessResult result = new ProcessExecutor()
                .command("./mvnw", "spring-boot:run", "-q")
                .timeout(cfg.timeoutSec(), TimeUnit.SECONDS)
                .redirectOutput(Files.newOutputStream(logFile))
                .redirectErrorStream(true)
                .execute();
            
            int exitCode = result.getExitValue();

            // Verify output patterns
            String output = Files.readString(logFile);
            out.println("✅ Verifying output patterns...");
            
            int failedPatterns = 0;
            for (String pattern : cfg.successRegex()) {{
                if (output.matches("(?s).*" + pattern + ".*")) {{
                    out.println("  ✓ Found: " + pattern);
                }} else {{
                    err.println("  ❌ Missing: " + pattern);
                    failedPatterns++;
                }}
            }}

            Files.deleteIfExists(logFile);

            if (exitCode != 0) {{
                err.println("❌ Application exited with code: " + exitCode);
                exit(exitCode);
            }}

            if (failedPatterns > 0) {{
                err.println("❌ Failed pattern verification: " + failedPatterns + " patterns missing");
                exit(1);
            }}

            out.println("🎉 Integration test completed successfully!");

        }} finally {{{cleanup_code}
        }}
    }}

    private static void runCommand(String[] cmd, int timeoutSec) throws Exception {{
        ProcessResult result = new ProcessExecutor()
            .command(cmd)
            .timeout(timeoutSec, TimeUnit.SECONDS)
            .redirectOutput(System.out)
            .redirectError(System.err)
            .execute();
            
        int exit = result.getExitValue();
        if (exit != 0) {{
            throw new RuntimeException("Command failed with exit code " + exit + ": " + String.join(" ", cmd));
        }}
    }}
}}'''

def create_integration_test(module_path: str, complexity: str = 'simple', force: bool = False):
    """Create integration test files for a Spring AI example"""
    module_dir = pathlib.Path(module_path)
    if not module_dir.exists():
        print(f"❌ Module directory not found: {module_path}")
        sys.exit(1)
    
    if not (module_dir / "pom.xml").exists():
        print(f"❌ No pom.xml found in {module_path}. Is this a Maven project?")
        sys.exit(1)
    
    integration_dir = module_dir / "integration-tests"
    
    # Check if integration tests already exist
    if integration_dir.exists() and not force:
        print(f"⚠️  Integration tests already exist in {integration_dir}")
        print("Use --force to overwrite existing files")
        sys.exit(1)
    
    integration_dir.mkdir(exist_ok=True)
    
    # Get module information
    module_info = get_module_info(module_path)
    config = get_config_template(complexity)
    
    # Create ExampleInfo.json
    config_file = integration_dir / "ExampleInfo.json"
    with config_file.open("w") as f:
        json.dump(config, f, indent=2)
    
    # Create JBang launcher
    launcher_file = integration_dir / f"Run{module_info['class_name']}.java"
    launcher_content = generate_jbang_launcher(module_info, config)
    with launcher_file.open("w") as f:
        f.write(launcher_content)
    
    print(f"✅ Created integration test for {module_path}")
    print(f"   📄 {config_file}")
    print(f"   ☕ {launcher_file}")
    print(f"   🎯 Complexity: {complexity}")
    print(f"   ⏱️  Timeout: {config['timeoutSec']}s")
    print(f"   🔍 Success patterns: {len(config['successRegex'])}")
    print(f"\n🧪 To test locally:")
    print(f"   cd {module_path}")
    print(f"   jbang integration-tests/Run{module_info['class_name']}.java")
    
    # Show configuration suggestions
    print(f"\n💡 Configuration suggestions:")
    if complexity == 'simple':
        print("   - Review success patterns in ExampleInfo.json")
        print("   - Adjust timeout if needed")
    elif complexity == 'mcp':
        print("   - Verify setupCommands match your database/service setup")
        print("   - Add cleanup commands if needed")
        print("   - Check MCP-specific environment variables")
    else:
        print("   - Fine-tune success patterns for your specific workflow")
        print("   - Consider adding setup/cleanup commands if needed")

def main():
    """Main CLI function"""
    parser = argparse.ArgumentParser(
        description="Scaffold integration test files for Spring AI examples",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Create simple integration test
  python3 scripts/scaffold_integration_test.py kotlin/kotlin-hello-world
  
  # Create complex integration test with longer timeout
  python3 scripts/scaffold_integration_test.py agentic-patterns/chain-workflow --complexity complex
  
  # Create MCP integration test with database setup
  python3 scripts/scaffold_integration_test.py model-context-protocol/sqlite/simple --complexity mcp
        """
    )
    
    parser.add_argument("module_path", 
                       help="Path to the module directory (e.g., kotlin/kotlin-hello-world)")
    parser.add_argument("--complexity", "-c", 
                       choices=['simple', 'complex', 'mcp'], 
                       default='simple',
                       help="Complexity level for the integration test")
    parser.add_argument("--force", "-f", 
                       action="store_true",
                       help="Overwrite existing integration test files")
    
    args = parser.parse_args()
    
    create_integration_test(args.module_path, args.complexity, args.force)

if __name__ == "__main__":
    main()